
#pragma once

#define DNSFILTER_DEVICE_NAME   L"\\Device\\DNSFILTER"
#define DNSFILTER_SYMBOLIC_NAME L"\\DosDevices\\Global\\DNSFILTER"
#define DNSFILTER_DOS_NAME      L"\\\\.\\DNSFILTER"

#define	DNSFILTER_IOCTL_INIT_FILTERS        CTL_CODE(FILE_DEVICE_NETWORK, 0x1, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_RELEASE_RESORCE     CTL_CODE(FILE_DEVICE_NETWORK, 0x2, METHOD_BUFFERED, FILE_ANY_ACCESS)

#define	DNSFILTER_IOCTL_WAIT_DNS_QUERY          CTL_CODE(FILE_DEVICE_NETWORK, 0x3, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_WAIT_FLOW_ESTABLISED    CTL_CODE(FILE_DEVICE_NETWORK, 0x4, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_READ_UDP_QUERY          CTL_CODE(FILE_DEVICE_NETWORK, 0x5, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_WAIT_UDP_RESPONCE       CTL_CODE(FILE_DEVICE_NETWORK, 0x6, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_APPROVAL_UDP_QUERY      CTL_CODE(FILE_DEVICE_NETWORK, 0x7, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_REPLACE_UDP_QUERY       CTL_CODE(FILE_DEVICE_NETWORK, 0x8, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_GET_FLOW_STATUS         CTL_CODE(FILE_DEVICE_NETWORK, 0x9, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_READ_UDP_RESPONCE       CTL_CODE(FILE_DEVICE_NETWORK, 0xA, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_APPROVAL_UDP_RESPONCE   CTL_CODE(FILE_DEVICE_NETWORK, 0xB, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_REPLACE_UDP_RESPONCE    CTL_CODE(FILE_DEVICE_NETWORK, 0xC, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_READ_TCP_QUERY          CTL_CODE(FILE_DEVICE_NETWORK, 0xD, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_WAIT_TCP_RESPONCE       CTL_CODE(FILE_DEVICE_NETWORK, 0xE, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_APPROVAL_TCP_QUERY      CTL_CODE(FILE_DEVICE_NETWORK, 0xF, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_INJECT_TCP_QUERY        CTL_CODE(FILE_DEVICE_NETWORK, 0x10, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_READ_TCP_RESPONCE       CTL_CODE(FILE_DEVICE_NETWORK, 0x11, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_WAIT_TCP_NEW_MESSAGE    CTL_CODE(FILE_DEVICE_NETWORK, 0x12, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_APPROVAL_TCP_RESPONCE   CTL_CODE(FILE_DEVICE_NETWORK, 0x13, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_INJECT_TCP_RESPONCE     CTL_CODE(FILE_DEVICE_NETWORK, 0x14, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define	DNSFILTER_IOCTL_WAIT_FLOW_DONE          CTL_CODE(FILE_DEVICE_NETWORK, 0x15, METHOD_BUFFERED, FILE_ANY_ACCESS)

// {B27C0183-5DF1-4753-95BE-DA972A0F7D42}
DEFINE_GUID(DNS_FILTER_ALE_FLOW_ESTABLISHED_CALLOUT_V4,
0xb27c0183, 0x5df1, 0x4753, 0x95, 0xbe, 0xda, 0x97, 0x2a, 0xf, 0x7d, 0x42);

// {2F793FDF-1696-41C2-AC2F-842D2FB9E6DF}
DEFINE_GUID(DNS_FILTER_ALE_FLOW_ESTABLISHED_CALLOUT_V6,
    0x2f793fdf, 0x1696, 0x41c2, 0xac, 0x2f, 0x84, 0x2d, 0x2f, 0xb9, 0xe6, 0xdf);

// {97D36DD3-EAFD-43E5-B40B-B5EE6FA599B7}
DEFINE_GUID(DSN_FILTER_STREAM_CALLOUT_V4,
0x97d36dd3, 0xeafd, 0x43e5, 0xb4, 0xb, 0xb5, 0xee, 0x6f, 0xa5, 0x99, 0xb7);

// {5A08ABFF-BEC1-4590-B262-7A6765EF92C2}
DEFINE_GUID(DSN_FILTER_STREAM_CALLOUT_V6,
    0x5a08abff, 0xbec1, 0x4590, 0xb2, 0x62, 0x7a, 0x67, 0x65, 0xef, 0x92, 0xc2);

// {1E310377-93A7-4D43-BEAF-56C03F66AF78}
DEFINE_GUID(DSN_FILTER_DATAGRAM_DATA_CALLOUT_V4, 
0x1e310377, 0x93a7, 0x4d43, 0xbe, 0xaf, 0x56, 0xc0, 0x3f, 0x66, 0xaf, 0x78);

// {BCBB7D38-A51D-411F-89F3-9C9AC70D836C}
DEFINE_GUID(DSN_FILTER_DATAGRAM_DATA_CALLOUT_V6,
    0xbcbb7d38, 0xa51d, 0x411f, 0x89, 0xf3, 0x9c, 0x9a, 0xc7, 0xd, 0x83, 0x6c);


typedef enum _context_state
{
    csNotRun = 0,
    csWaitFlowDoneStarted,          //    fc 01
    csWaitQueryStarted,             //    fc 02
    csWaitFlowEstablishedStarted,   //    fc 03
    csUdpFlowEstablished,           // fd fc 04
    csUdpWaitReadQuery,             // fd fc 05
    csUdpWaitResponceStarted,       // fd fc 06
    csUdpWaitApprovalQuery,         // fd fc 07
    csUdpPermitQueryPended,         // fd fc 08
    csUdpWaitPermitQuery,           // fd fc 09
    csUdpWaitReplaceQuery,          // fd fc 10
    csUdpReplaceQueryPended,        // fd fc 11
    csUdpWaitReplaceQueryDone,      // fd fc 12
    csUdpQueryDiscarded,            // fd fc 13
    csUdpPermitQueryDone,           // fd fc 14
    csUdpReplaceQueryDone,          // fd fc 15
    csUdpWaitQueryInjectDone,       // fd fc 16
    csUdpWaitReadResponce,          // fd fc 17
    csUdpWaitApprovalResponce,      // fd fc 18
    csUdpPermitResponcePended,      // fd fc 19
    csUdpWaitPermitResponce,        // fd fc 20
    csUdpWaitReplaceResponce,       // fd fc 21
    csUdpReplaceResponcePended,     // fd fc 22
    csUdpWaitReplaceResponceDone,   // fd fc 23
    csUdpFlowDone,                  // fd fc 24
    csTcpFlowEstablished,           // fd fc 25
    csTcpQueryMoreData01,           // fd fc 26
    csTcpQueryMoreData02,           // fd fc 27
    csTcpWaitReadQuery,             // fd fc 28
    csTcpWaitApprovalQuery,         // fd fc 29
    csTcpWaitResponceStarted,       // fd fc 30
    csTcpWaitReplaceQuery,          // fd fc 31
    csTcpQueryDiscarded,            // fd fc 32
    csTcpPermitQueryPended,         // fd fc 33
    csTcpWaitPermitQuery,           // fd fc 34
    csTcpPermitQueryDone,           // fd fc 35
    csTcpWaitQueryInjectDone,       // fd fc 36
    csTcpReplaceQueryPended,        // fd fc 37
    csTcpWaitReplaceQueryDone,      // fd fc 38
    csTcpReplaceQueryDone,          // fd fc 39
    csTcpWaitReadResponce,          // fd fc 40
    csTcpResponceMoreData01,        // fd fc 41
    csTcpResponceMoreData02,        // fd fc 42
    csTcpResponceMoreData03,        // fd fc 43
    csTcpWaitApprovalResponce,      // fd fc 44
    csTcpPermitResponcePended,      // fd fc 45
    csTcpWaitPermitResponce,        // fd fc 46
    csTcpPermitResponceDone,        // fd fc 47
    csTcpWaitResponceInjectDone,    // fd fc 48
    csTcpWaitReplaceResponce,       // fd fc 49
    csTcpResponceDiscarded,         // fd fc 50
    csTcpWaitNewMessageStarted,     // fd fc 51
    csTcpReplaceResponcePended,     // fd fc 52
    csTcpWaitReplaceResponceDone,   // fd fc 53
    csTcpReplaceResponceDone,       // fd fc 54
    csFlowDeleted,                  // fd fc 55
    csFileClosed,                   //    fc 56
    csDnsError,                     // fd    57
    csMaxValue                      //       58
}
context_state;

#pragma pack(push, 1)
#pragma warning(push)
#pragma warning(disable : 4214)
typedef struct _IP_HEADER
{
    // -- 0
    BYTE        _IHL                : 4;
    BYTE        _Version            : 4;
    BYTE        _Type_of_Service;
    WORD        _Total_Length;
    // -- 1
    WORD        _Identification;
    WORD        _Fragment_Offset    : 13;
    WORD        _Flags              : 3;
    // -- 2
    BYTE        _Time_to_Live;
    BYTE        _Protocol;
    WORD        _Header_Checksum;
    // -- 3
    DWORD       _Source_Address;
    // -- 4
    DWORD       _Destination_Address;
    // -- 5     -- minimal
    //DWORD       _Options[variable length];
} IP_HEADER, *PIP_HEADER;

typedef struct _IP6_BASE_HEADER
{
    // -- 0
    DWORD   _Version                : 4;
    DWORD   _TrafficClass           : 8;
    DWORD   _FlowLabel              : 20;
    // -- 1
    WORD    _PayloadLength;
    BYTE    _NextHeader;
    BYTE    _HopLimit;
    // -- 2
    FWP_BYTE_ARRAY16    _SourceAddress;
    // -- 6
    FWP_BYTE_ARRAY16    _DestinationAddress;
    // -- 10
} IP6_BASE_HEADER, *PIP6_BASE_HEADER;
#pragma warning(pop)

typedef struct _UDP_HEADER
{
    UINT16 srcPort;
    UINT16 destPort;
    UINT16 length;
    UINT16 checksum;
} UDP_HEADER, *PUDP_HEADER;

typedef struct _UDP_PSEVDO_PREFIX
{
    DWORD   _source_address;
    DWORD   _destination_address;
    BYTE    _zero;
    BYTE    _protocol;
    WORD    _UDP_length;
} UDP_PSEVDO_PREFIX, *PUDP_PSEVDO_PREFIX;

typedef struct _UDP6_PSEVDO_PREFIX
{
    FWP_BYTE_ARRAY16    _SourceAddress;
    FWP_BYTE_ARRAY16    _DestinationAddress;
    DWORD               _ULPacketLength;
    BYTE                _zero[3];
    BYTE                _NextHeader;
} UDP6_PSEVDO_PREFIX, *PUDP6_PSEVDO_PREFIX;
#pragma pack(pop)

__inline WORD ones_complement_sum(
    WORD wArg1,
    WORD wArg2
    )
{
    DWORD   dwResult = wArg1 + wArg2;
    return (WORD)(dwResult & 0xFFFF) + (WORD)(dwResult >> 16);
}

typedef struct _FLOW_DATA
{
    struct _FLOW_DATA*  pThis;
    LIST_ENTRY          listEntry;
    LIST_ENTRY          threadListEntry;
    LIST_ENTRY          stFileListEntry;
    context_state       enContextState;
    context_state       arContextStateStack[20];
    WDFFILEOBJECT       wdfFlowFileObject;
    WDFQUEUE            wdfFlowQueue;
    WDFQUEUE            wdfWaitFlowDoneQueue;
    WDFQUEUE            wdfWaitDnsQueryQueue;
    WDFQUEUE            wdfWaitFlowEstablishedQueue;
    WDFQUEUE            wdfUdpQueryPermitQueue;
    WDFQUEUE            wdfUdpQueryReplaceQueue;
    WDFQUEUE            wdfUdpResponcePermitQueue;
    WDFQUEUE            wdfUdpResponceReplaceQueue;
    IPPROTO             enIpProto;
    FWP_DIRECTION       enPacketDirection;
    UINT64              flowHandle;
    UINT32              nRemoteAddressV4;
    UINT32              nRemoteAddressV4N;
    IF_INDEX            interfaceIndex;
    IF_INDEX            subInterfaceIndex;
    PNET_BUFFER_LIST    pUdpQueryBufferList;
    PNET_BUFFER_LIST    pUdpQueryCloneBufferList;
    PMDL                pUdpQueryMdl;
    PNET_BUFFER_LIST    pUdpQueryReplaceBufferList;
    UINT32              ulUdpQueryReplaceDataSize;
    UINT32              ulUdpQueryBufferSize;
    UINT32              ulUdpQueryPacketOffset;
    UINT32              ulUdpQueryDataOffset;
    UINT32              ulUdpQueryDataLength;
    COMPARTMENT_ID      enUdpQueryCompartmentID;
    UINT32              ulUdpQueryIpHeaderSize;
    UINT32              ulUdpQueryTransportHeaderSize;
    WDFQUEUE            wdfWaitUdpResponceQueue;
    PNET_BUFFER_LIST    pUdpResponceBufferList;
    PNET_BUFFER_LIST    pUdpResponceCloneBufferList;
    UDP_HEADER          stDnsResonceUdpHeader;
    UINT32              ulUdpResponceBufferSize;
    UINT32              ulUdpResponceDataOffset;
    SIZE_T              nUdpResponceDataLength;
    COMPARTMENT_ID      enUdpResponceCompartmentID;
    UINT32              ulUdpResponceIpHeaderSize;
    UINT32              ulUdpResponceTransportHeaderSize;
    UINT64              hUdpResponceEndpointHandle;
    UINT64              hUdpInjectEndpointHandle;
    FWPS_TRANSPORT_SEND_PARAMS stUdpResponceSendParams;
    PMDL                pUdpResponceMdl;
    PNET_BUFFER_LIST    pUdpResponceReplaceBufferList;
    UINT32              ulUdpResponceReplaceDataSize;
    UINT64              hTcpQueryFlowID;
    PNET_BUFFER_LIST    pTcpQueryBufferList;
    SIZE_T              nTcpQueryLength;
    WDFQUEUE            wdfWaitTcpResponceQueue;
    WDFQUEUE            wdfTcpQueryPermitQueue;
    PMDL                pTcpQueryMdl;
    PNET_BUFFER_LIST    pTcpQueryInjectBufferList;
    size_t              nTcpQueryInjectDataSize;
    WDFQUEUE            wdfTcpQueryInjectQueue;
    UINT64              hTcpResponceFlowID;
    PNET_BUFFER_LIST    pTcpResponceBufferList;
    SIZE_T              nTcpResponceLength;
    WDFQUEUE            wdfTcpResponcePermitQueue;
    WDFQUEUE            wdfWaitTcpNewMessageQueue;
    PMDL                pTcpResponceMdl;
    PNET_BUFFER_LIST    pTcpResponceInjectBufferList;
    size_t              nTcpResponceInjectDataSize;
    WDFQUEUE            wdfTcpResponceInjectQueue;
    BOOLEAN             bIPv6;
    BOOLEAN             bPadValue1;
    BOOLEAN             bPadValue2;
    BOOLEAN             bPadValue3;
    FWP_BYTE_ARRAY16    stRemoteAddressV6;
} FLOW_DATA, *PFLOW_DATA;

typedef enum _dns_approval_action
{
    aaPermit,
    aaModify,
    aaDiscard
}
dns_approval_action;

typedef struct _UDP_QUERY_APPROVAL
{
    dns_approval_action _enApprovalAction;
}
UDP_QUERY_APPROVAL, *PUDP_QUERY_APPROVAL;

typedef struct _UDP_RESPONCE_APPROVAL
{
    dns_approval_action _enApprovalAction;
}
UDP_RESPONCE_APPROVAL, *PUDP_RESPONCE_APPROVAL;

typedef struct _TCP_QUERY_APPROVAL
{
    dns_approval_action _enApprovalAction;
}
TCP_QUERY_APPROVAL, *PTCP_QUERY_APPROVAL;

typedef struct _TCP_RESPONCE_APPROVAL
{
    dns_approval_action _enApprovalAction;
}
TCP_RESPONCE_APPROVAL, *PTCP_RESPONCE_APPROVAL;

typedef struct _IP4ADDR_RANGE_STRUCT
{
    UINT32 _ulLowValue;
    UINT32 _ulHighValue;
}
IP4ADDR_RANGE_STRUCT, *PIP4ADDR_RANGE_STRUCT;

typedef struct _IP4SUBNET_STRUCT
{
    UINT32 _ulIpAddr;
    UINT32 _ulIpMask;
}
IP4SUBNET_STRUCT, *PIP4SUBNET_STRUCT;

typedef struct _IPV6_ADDRESS_STRUCT
{
    UINT8   _IPv6Addr[16];
    UINT32  _PrefixLength;
}IPV6_ADDRESS_STRUCT, *PIPV6_ADDRESS_STRUCT;

typedef struct _ADDRESSES_DESCRIPTOR
{
    int m_nPublicIpCount;
    UINT32* m_pPublicIpArray;
    int m_nPrivateIpCount;
    UINT32* m_pPrivateIpArray;
    int m_nPublicRangeCount;
    PIP4ADDR_RANGE_STRUCT m_pPublicRangeArray;
    int m_nPrivateRangeCount;
    PIP4ADDR_RANGE_STRUCT m_pPrivateRangeArray;
    int m_nPublicSubnetCount;
    PIP4SUBNET_STRUCT m_pPublicSubnetArray;
    int m_nPrivateSubnetCount;
    PIP4SUBNET_STRUCT m_pPrivateSubnetArray;
    int m_nPublicIPV6AddrCount;
    PIPV6_ADDRESS_STRUCT m_pPublicIPV6AddrArray;
    int m_nPrivateIPV6AddrCount;
    PIPV6_ADDRESS_STRUCT m_pPrivateIPV6AddrArray;
    PBYTE m_pDataArray;
} ADDRESSES_DESCRIPTOR, *PADDRESSES_DESCRIPTOR;

static const FWP_BYTE_ARRAY16 c_aIPv6MaskArray[] = {
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   0
    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   1
    { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   2
    { 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   3
    { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   4
    { 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   5
    { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   6
    { 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   7
    { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   8
    { 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //   9
    { 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  10
    { 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  11
    { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  12
    { 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  13
    { 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  14
    { 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  15
    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  16
    { 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  17
    { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  18
    { 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  19
    { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  20
    { 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  21
    { 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  22
    { 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  23
    { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  24
    { 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  25
    { 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  26
    { 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  27
    { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  28
    { 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  29
    { 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  30
    { 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  31
    { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  32
    { 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  33
    { 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  34
    { 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  35
    { 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  36
    { 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  37
    { 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  38
    { 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  39
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  40
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  41
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  42
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  43
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  44
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  45
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  46
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  47
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  48
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  49
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  50
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  51
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  52
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  53
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  54
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  55
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  56
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  57
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  58
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  59
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  60
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  61
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  62
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  63
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  64
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  65
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  66
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  67
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  68
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  69
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  70
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  71
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  72
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  73
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  74
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  75
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  76
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  77
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  78
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  79
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  80
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  81
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  82
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  83
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  84
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  85
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  86
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  87
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }, //  88
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 }, //  89
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00 }, //  90
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00 }, //  91
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 }, //  92
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00 }, //  93
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00 }, //  94
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00 }, //  95
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }, //  96
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00 }, //  97
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00 }, //  98
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00 }, //  99
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 }, // 100
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00 }, // 101
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00 }, // 102
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00 }, // 103
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }, // 104
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00 }, // 105
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00 }, // 106
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00 }, // 107
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 }, // 108
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00 }, // 109
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00 }, // 110
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00 }, // 111
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }, // 112
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00 }, // 113
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 }, // 114
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00 }, // 115
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00 }, // 116
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00 }, // 117
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00 }, // 118
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00 }, // 119
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }, // 120
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }, // 121
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0 }, // 122
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0 }, // 123
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0 }, // 124
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8 }, // 125
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc }, // 126
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe }, // 127
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, // 128
};

static const PUINT64 c_aQWMaskArray = (PUINT64) c_aIPv6MaskArray;
static const IPV6_ADDRESS_STRUCT c_stGlobalIPv6Subnet =
{
    { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
    3
};
static const PIPV6_ADDRESS_STRUCT c_pGlobalIPv6Subnet = (const PIPV6_ADDRESS_STRUCT) &c_stGlobalIPv6Subnet;
static const FWP_BYTE_ARRAY16 c_stIPv6LocalAdddess = 
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };

__inline BOOLEAN bfIsIPv6AddressesEqual(
    const FWP_BYTE_ARRAY16*   pIPv6Address1,
    const FWP_BYTE_ARRAY16*   pIPv6Address2
    )
{
    const PUINT64   pDoubleQword1 = (PUINT64) pIPv6Address1;
    const PUINT64   pDoubleQword2 = (PUINT64) pIPv6Address2;
    BOOLEAN         bReturn;
    bReturn = (pDoubleQword1[0] == pDoubleQword2[0]);
    bReturn = bReturn && (pDoubleQword1[1] == pDoubleQword2[1]);
    return bReturn;
}

__inline BOOLEAN bfIPv6AddressInIPv6Subnet(
    const FWP_BYTE_ARRAY16*    pIPv6Address,
    const PIPV6_ADDRESS_STRUCT pIPv6Subnet
    )
{
    const UINT32    nMaskIndex = (pIPv6Subnet->_PrefixLength << 1);
    const PUINT64   pDoubleQword = (PUINT64) pIPv6Address;
    const PUINT64   aIPv6SubnetArray = (PUINT64) pIPv6Subnet;
    UINT64          aIPv6Address[2];
    BOOLEAN         bReturn;
    aIPv6Address[0] = pDoubleQword[0];
    aIPv6Address[1] = pDoubleQword[1];
    aIPv6Address[0] &= c_aQWMaskArray[nMaskIndex];
    aIPv6Address[1] &= c_aQWMaskArray[nMaskIndex+1];
    bReturn = (aIPv6SubnetArray[0] == aIPv6Address[0]);
    bReturn = bReturn && (aIPv6SubnetArray[1] == aIPv6Address[1]);
    return bReturn;
}

__inline void IPv6CopyAddress(
    FWP_BYTE_ARRAY16*       pDestAddress,
    const FWP_BYTE_ARRAY16* pSrcAddress
    )
{
    const PUINT64   pDoubleQwordSrc  = (PUINT64) pSrcAddress;
    PUINT64         pDoubleQwordDest = (PUINT64) pDestAddress;
    pDoubleQwordDest[0] = pDoubleQwordSrc[0];
    pDoubleQwordDest[1] = pDoubleQwordSrc[1];
}
